﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FUSE.AzureConfig.Tasks
{
    /// <summary>
    /// Processed Azure configuration
    /// </summary>
    public class AzureConfig
    {
        public AzureConfig(string name)
        {
            this.Name = name;
            this.Roles = new Dictionary<string, AzureRoleDetails>();
            this.Environments = new Dictionary<string, AzureEnvironment>();
        }

        public AzureConfig(string name, 
            IDictionary<string, AzureRoleDetails> roles,
            IDictionary<string, AzureEnvironment> envs)
        {
            this.Name = name;
            this.Roles = roles;
            this.Environments = envs;
        }

        public string Name { get; private set; }

        public IDictionary<string, AzureRoleDetails> Roles { get; private set; }

        public IDictionary<string, AzureEnvironment> Environments { get; private set; }
    }

    public class AzureRoleDetails
    {
        public AzureRoleDetails(string roleName)
        {
            this.RoleName = roleName;
            this.ConfigurationSettingKeys = new HashSet<string>();
        }

        public string RoleName { get; private set; }

        public string RoleType { get; set; }

        public ISet<string> ConfigurationSettingKeys { get; private set; }
    }

    public class AzureEnvironment
    {
        public static AzureEnvironment FromParent(string envName, AzureEnvironment parent)
        {
            var env = new AzureEnvironment(envName);
            foreach (var r in parent.Roles)
            {
                var newR = new AzureRoleEnvironmentDetails(r.Value.Details);
                newR.Instances = r.Value.Instances;
                newR.ConfigSettings.AddSettings(r.Value.ConfigSettings.Settings);
                newR.ConfigSettings.AddMissing(r.Value.ConfigSettings.MissingSettings);
                newR.Certificates = new Dictionary<string,AzureCertificate>(r.Value.Certificates);
                env.Roles.Add(r.Key, newR);
            }

            return env;
        }

        public AzureEnvironment(string envName)
        {
            this.EnvName = envName;
            this.Roles = new Dictionary<string, AzureRoleEnvironmentDetails>();
        }

        public string EnvName { get; private set; }

        public IDictionary<string, AzureRoleEnvironmentDetails> Roles { get; private set; }
    }

    public class AzureRoleEnvironmentDetails
    {
        public AzureRoleEnvironmentDetails(AzureRoleDetails roleDetails)
        {
            this.Details = roleDetails;
            this.ConfigSettings = new AzureConfigSettings();
            this.Certificates = new Dictionary<string, AzureCertificate>();
        }

        public AzureRoleDetails Details { get; private set; }

        public string RoleName { get { return this.Details.RoleName; } }

        public int Instances { get; set; }

        public AzureConfigSettings ConfigSettings { get; set; }

        public Dictionary<string, AzureCertificate> Certificates { get; set; }
    }

    public class AzureCertificate
    {
        public string Thumbprint { get; set; }

        public string ThumbprintAlgorithm { get; set; }
    }

    public class AzureConfigSettings
    {
        public AzureConfigSettings()
        {
            this.Settings = new Dictionary<string, string>();
        }

        public IDictionary<string, string> Settings { get; private set; }

        private HashSet<string> _missing = new HashSet<string>();

        public ISet<string> MissingSettings
        {
            get
            {
                var found = _missing.Intersect(this.Settings.Keys);
                if (found.Any())
                {
                    _missing = new HashSet<string>(_missing.Except(found));
                }
                return _missing;
            }
        }

        public void AddSettings(IDictionary<string, string> settings)
        {
            foreach (var s in settings)
                this.Settings[s.Key] = s.Value;
        }

        public void AddMissing(ISet<string> possiblyMissing)
        {
            foreach (var m in possiblyMissing.Except(this.Settings.Keys))
                this.MissingSettings.Add(m);
        }
    }
}
